﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Principal;
using System.Runtime.InteropServices;

namespace MyPublisher.Storage.Common
{
    public class NtfsStorage : Storage
    {
        public bool NeedImpersonate 
        {
            get 
            { 
                return !string.IsNullOrEmpty(ConnectionString.Domain) &&
                    !string.IsNullOrEmpty(ConnectionString.UserName) &&
                    !string.IsNullOrEmpty(ConnectionString.Password);
            } 
        }
        private WindowsImpersonationContext ImpersonationContext { get; set; }

        public override string Type
        {
            get { return CommonStorageType.NTFS; }
        }

        public override void Open()
        {
            if (!Directory.Exists(ConnectionString.Path))
            {
                throw new
                    StorageException("Failed to open " + CommonStorageType.NTFS + " storage. Root path is not existent.");
            }
            if (NeedImpersonate)
            {
                ImpersonationContext =
                    Win32Interop.ImpersonateUser(ConnectionString.Domain, ConnectionString.UserName, ConnectionString.Password);
            }
        }

        public override void Close() 
        {
            if (ImpersonationContext != null)
            {
                try
                {
                    ImpersonationContext.Undo();
                }
                catch (Exception e)
                {
                    throw new StorageException("Failed to close storage.",e);
                }
            }
        }

        public override Stream OpenFile(string path)
         {
             ResolvePath(ref path);
             try
             {
                 return File.Open(path, FileMode.Open);
             }
             catch (Exception e)
             {
                 throw new StorageException("Failed to open file.", e);
             }
        }

        public override Stream CreateFile(string path)
        {
            ResolvePath(ref path);
            try
            {
                for (int start = 0, index = path.IndexOf('\\', start); index != -1 && start < path.Length; index = path.IndexOf('\\', start))
                {
                    string dir = path.Substring(0,index);
                    if (!Directory.Exists(dir))
                    {
                        Directory.CreateDirectory(dir);
                    }
                    start = index + 1;
                }
                return File.Open(path, FileMode.Create);
            }
            catch (Exception e)
            {
                throw new StorageException("Failed to create file.", e);
            }
        }

        public override bool IsFileExists(string path)
        {
            ResolvePath(ref path);
            return File.Exists(path);
        }

        public override void DeleteFile(string path)
        {
            ResolvePath(ref path);
            try
            {
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
            }
            catch (Exception e)
            {
                throw new StorageException("Failed to delete file.", e);
            }
        }

        public override string[] GetFiles(string path, string pattern, bool recursive)
        {
            ResolvePath(ref path);
            try
            {
                if (!Directory.Exists(path))
                {
                    return new string[] { };
                }
                SearchOption option = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
                return Directory.GetFiles(path, pattern, option);
            }
            catch (Exception e)
            {
                throw new StorageException("Failed to get file from "+path, e);
            }
        }


        public override void ResolvePath(ref string path)
        {
            string rootPath =
                ConnectionString.Path.Replace('/', '\\').TrimEnd(new char[] { '\\' });
            path = path.Replace('/','\\').TrimStart(new char[]{'\\'});
            path = rootPath + "\\" + path;
        }
    }
}
